#!/usr/bin/env python3
# 模拟炮舰主炮设计游戏


import pygame
from pygame.locals import *
from sys import exit
from threading import Thread,Lock,Timer
import time,math
from random import random
from lib.my_locale import msg

#273 上
#274 下
#275 左
#276 右
#32  空格
#27  ESC
class ship_gunner_app:
    def __init__(self):
        self.init_screen()
        self.init_params()
        
    def init_screen(self):
        DEBUG=1  # 0、1 切换全屏、窗口模式
        self.SCREEN_SIZE = (800, 600)
        self.Fullscreen = True
        if DEBUG==1:
            self.screen = pygame.display.set_mode(self.SCREEN_SIZE, 0, 32)
            self.Fullscreen = False
        else:
            self.screen = pygame.display.set_mode(self.SCREEN_SIZE, FULLSCREEN|DOUBLEBUF, 32)
    def init_params(self):
        self.LEFT_DOWN=False
        self.RIGHT_DOWN=False
        self.LOCK1 = Lock()
        self.is_alive = True
        self.background_image_filename = 'pics/bg2.png'
        self.ship_image_filename = 'pics/ship1.png'
        self.hole_img_filename = 'pics/hole1.png'
        self.background = pygame.image.load(self.background_image_filename).convert()
        self.ship1 = pygame.image.load(self.ship_image_filename).convert_alpha()
        self.hole1 = pygame.image.load(self.hole_img_filename).convert_alpha()

        self.font = pygame.font.Font("hei1.ttf", 18);
        self.font_height = self.font.get_linesize()

        pygame.event.set_blocked(None)
        pygame.event.set_allowed( [MOUSEBUTTONUP,KEYDOWN,KEYUP,QUIT,USEREVENT] )

        self.message = ''
        self.x = 358
        self.y = 273
        self.target = [self.x+50,self.y+15]
        self.gun_aim = (386,291)
        self.hit_dist = (0,0)
        self.hit_count = 0
        self.hit_report = ''
        self.damage = 0
        smoke1_filename = 'pics/smoke1.png'
        self.smoke1 = pygame.image.load(smoke1_filename).convert_alpha()
        self.bs = pygame.mixer.Sound('sound/bomb.wav')
        self.bs.set_volume(0.5)
            
    def verify_hit(self,effect_hit_dist,effect_wucha):
        hit_wucha = (effect_wucha[0]*(random()-0.5)*2,effect_wucha[1]*(random()-0.5)*2)
        self.hit_dist = (self.gun_aim[0]-self.target[0]+hit_wucha[0],self.gun_aim[1]-self.target[1]+hit_wucha[1])
        if self.hit_dist[0]*self.hit_dist[0] <= effect_hit_dist[0]*effect_hit_dist[0] and \
           self.hit_dist[1]*self.hit_dist[1] <= effect_hit_dist[1]*effect_hit_dist[1]:
            return True
        else:
            return False
            
    

    def hit_object(self, smoke_point,x,y ):
        self.LOCK1.acquire()
        smoke_point.append( (x,y) )
        self.damage += 50 - math.sqrt(x*x)
        self.hit_count += 1
        if self.damage<100:
            self.hit_report=msg['hit'] 
        else:
            self.hit_report=msg['damage']
        self.bs.play()
        self.LOCK1.release()

    def hit_missed(self):
        self.LOCK1.acquire()
        self.hit_report = msg['miss']
        self.LOCK1.release()

    def damage_ship(self,screen,x,y):
        self.LOCK1.acquire()
        screen.blit( self.font.render( msg['long_damage'] ,\
                                  False, (255, 0, 0)).convert_alpha(), (320, 200) )
        ship2 = pygame.image.load('pics/baozha1.png').convert_alpha()
        screen.blit(ship2,(x,y))
        screen.blit( self.font.render(msg['damage'], False, (255, 0, 0)).convert_alpha(), (10, self.font_height) )
        pygame.display.flip()
        
        self.bs.play()
        time.sleep(1)
        ship2 = pygame.image.load('pics/baozha2.png').convert_alpha()
        screen.blit(ship2,(x,y))
        pygame.display.flip()
        time.sleep(1)
        ship2 = pygame.image.load('pics/baozha3.png').convert_alpha()
        screen.blit(ship2,(x,y))
        pygame.display.flip()
        self.LOCK1.release()
        time.sleep(1)
        
    def event_cicle(self,distance):
        base_hit_dist = (45,12)
        effect_hit_dist = (base_hit_dist[0]*2000.0/distance,base_hit_dist[1]*2000.0/distance)
        base_wucha = (1.0,1.0)
        effect_wucha = (base_wucha[0]*distance/2000.0,base_wucha[1]*distance/2000.0)
        hit_time = distance/1000.0
        bt_win = (330,568,40,30)
        bt_quit = (390,568,40,30)
        fire = pygame.mixer.Sound( file="sound/fire.wav" )
        while self.is_alive:
            event = pygame.event.wait()
            d_time = time.time()-self.start_time
            self.d_y = int(math.sin( math.pi*d_time/4.0)*30)
            self.target = [self.x+50,self.y+self.d_y+self.dy+15]
            self.LOCK1.acquire()
            if event.type == QUIT:
                self.is_alive = False
                self.LOCK1.release()
                break
            elif event.type == KEYDOWN:
                if event.key == 273:
                    self.dy += 1
                    self.target[1] += 1
                elif event.key == 274:
                    self.dy -= 1
                    self.target[1] -=1
                elif event.key == 275:
                    self.RIGHT_DOWN = True
                elif event.key == 276:
                    self.LEFT_DOWN = True
                elif event.key == 32:
                    if time.time()-self.load_timestamp>5:
                        fire.play()
                        if self.verify_hit(effect_hit_dist,effect_wucha):
                            timer1 = Timer(hit_time,self.hit_object,args=(self.smoke_point,self.hit_dist[0]*distance/2000.0,10 ))
                            timer1.start()
                        else:
                            timer2 = Timer(hit_time,self.hit_missed)
                            timer2.start()
                        self.fire_count += 1
                        self.load_timestamp = time.time()
                elif event.key == 27:
                    self.is_alive = False
                    self.LOCK1.release()
                    break
            elif event.type == KEYUP:
                if event.key == 275:
                    self.RIGHT_DOWN = False
                elif event.key == 276:
                    self.LEFT_DOWN = False
            elif event.type == USEREVENT:
                if event.message=='h':
                    self.x -= 1
                    if self.LEFT_DOWN:
                        self.x+=3
                    elif self.RIGHT_DOWN:
                        self.x-=2
            elif event.type == MOUSEBUTTONUP:
                if self.isOver(bt_win):
                    self.Fullscreen = not self.Fullscreen
                    if self.Fullscreen:
                        self.screen = pygame.display.set_mode(self.SCREEN_SIZE, FULLSCREEN|DOUBLEBUF, 32)
                    else:
                        self.screen = pygame.display.set_mode(self.SCREEN_SIZE, 0, 32)
                if self.isOver(bt_quit):
                    self.is_alive = False
                    self.LOCK1.release()
                    break
            self.LOCK1.release()

    def shot_main( self,distance=4000 ):
        clock1 = pygame.time.Clock()
        self.init_params()
        self.start_time = time.time()
        self.dy=0  #垂直射角调整量
        self.d_y=0
        self.smoke_point = []
        self.fire_count = 0
        bt_win = (330,568,40,30)
        bt_quit = (390,568,40,30)
        self.load_timestamp = time.time()-6
        mission_time = time.time()
        t_event= Thread(target=self.event_cicle,args=(distance,))
        t_event.start()
        while self.is_alive:
            self.LOCK1.acquire()
            d_time = time.time()-self.start_time
            self.d_y = int(math.sin( math.pi*d_time/4.0)*30)
            self.target = [self.x+50,self.y+self.d_y+self.dy+15]
            self.x -= 1
            if self.LEFT_DOWN:
                self.x+=3
            elif self.RIGHT_DOWN:
                self.x-=2
            if time.time()-self.load_timestamp>5:
                self.message = msg['ready_fire']
            else:
                self.message = msg['loading']
            self.screen.fill((255, 255, 255))
            self.screen.blit(self.background, (0,self.d_y+self.dy))
            self.screen.blit(self.ship1,(self.x,self.y+self.d_y+self.dy))
            self.screen.blit(self.hole1,(0,0))
            for p in self.smoke_point:
                self.show_smoke(self.screen,self.target[0]+p[0],self.target[1]+p[1])
            pygame.draw.circle( self.screen,(255,0,0),self.gun_aim,2 )
            self.screen.blit( self.font.render(msg['count_fire'].format(self.fire_count), False, (0, 255, 0)).convert_alpha(), (10, 0) )
            self.screen.blit( self.font.render(msg['count_hit'].format(self.hit_count,self.damage), False, (0, 255, 0)).convert_alpha(), (200, 0) )
            self.screen.blit( self.font.render( self.hit_report, False, (255, 0, 0)).convert_alpha(), (10, self.font_height) )
            self.screen.blit( self.font.render( self.message, False, (255, 0, 0)).convert_alpha(), (300, self.font_height) )
            self.screen.blit( self.font.render(msg['distance'] .format(distance),\
                          False, (0, 255, 0)).convert_alpha(), (600, 0) )
            if self.Fullscreen:
                win_mode = msg['win']
            else:
                win_mode = msg['fs']
            self.draw_text_button(self.screen,bt_win,win_mode)
            self.draw_text_button(self.screen,bt_quit,msg['quit'])
            pygame.display.flip()
            self.LOCK1.release()
            if self.damage>=100:
                self.is_alive = False
                time.sleep(1)
                self.damage_ship(self.screen,self.x,self.y+self.d_y+self.dy)
                break
            p_x = self.target[0]-self.gun_aim[0]
            if p_x*p_x>40000 or time.time()-mission_time >600:
                self.screen.blit( self.font.render( msg['fail'], False, (255, 0, 0)).convert_alpha(),  (320, 200)  )
                pygame.display.flip()
                time.sleep(2)
                self.is_alive = False
                break
            clock1.tick(40)
        


    def show_smoke(self,screen,x,y):
        screen.blit(self.smoke1,(x-10,y-60))

    def ask_todo(self,dist):
        self.screen.fill((0,0,0))
        self.screen.blit( self.font.render( msg['success'].format(dist),\
                                  False, (255, 0, 0)).convert_alpha(), (270, 150) )
        bt1 = (300,350,170,30)
        bt2 = (300,200,170,30) #dist-1000
        bt3 = (300,250,170,30) #dist
        bt4 = (300,300,170,30) #dist+1000
        self.draw_text_button(self.screen,bt1,msg['quit'])
        self.draw_text_button(self.screen,bt2,msg['fire_dist'].format(dist-1000))
        self.draw_text_button(self.screen,bt3,msg['fire_dist'].format(dist))
        self.draw_text_button(self.screen,bt4,msg['fire_dist'].format(dist+1000))
        pygame.display.flip()
        ret = True
        while True:
            event = pygame.event.wait()
            if event.type == MOUSEBUTTONUP:
                if self.isOver(bt1):
                    ret = 0
                    break
                elif self.isOver(bt2):
                    ret = dist-1000
                    break
                elif self.isOver(bt3):
                    ret = dist
                    break
                elif self.isOver(bt4):
                    ret = dist+1000
                    break
        return ret

    def draw_text_button(self,screen,rect=(10,10,10,10),text='b'):
        pygame.draw.rect(screen,(0,255,0),rect,2)
        screen.blit( self.font.render( text, False, (0, 255, 0)).convert_alpha(), (rect[0]+3, rect[1]+5) )

    def isOver(self,rect=(0,0,1,1)):
        point_x,point_y = pygame.mouse.get_pos()
        in_x = rect[0] < point_x <rect[0]+rect[2]
        in_y = rect[1] < point_y <rect[1]+rect[3]
        return in_x and in_y
    
if __name__=='__main__':
    dist=4000
    pygame.init()
    pygame.mixer.init()
    app1 = ship_gunner_app()
    while True:
        app1.shot_main(dist)
        dist = app1.ask_todo(dist)
        if dist == 0:
            break
